﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace Kyoh.Lib.WinForms
{
    /// <summary><see cref="DataGridView"/> の列の表示状態をシリアライズするクラス。</summary>
    [XmlRoot("Profiles")]
    public class DataGridViewColumnProfiles : IXmlSerializable
    {
        private readonly List<DataGridViewColumnProfile> _profiles;

        /// <summary><see cref="DataGridViewColumnProfiles"/> の新しいインスタンスを初期化します。</summary>
        public DataGridViewColumnProfiles()
        {
            _profiles = new List<DataGridViewColumnProfile>();
        }

        /// <summary><see cref="DataGridViewColumnProfiles"/> の新しいインスタンスを初期化します。</summary>
        public DataGridViewColumnProfiles(DataGridView dgv)
            : this()
        {
            GetProfile(dgv);
        }

        /// <summary><see cref="DataGridView"/> から、列の表示状態を取得します。</summary>
        /// <param name="dgv"><see cref="DataGridView"/>。</param>
        public void GetProfile(DataGridView dgv)
        {
            _profiles.Clear();
            foreach (DataGridViewColumn col in dgv.Columns)
                _profiles.Add(new DataGridViewColumnProfile(col));
        }

        /// <summary><see cref="DataGridView"/> に、列の表示状態を設定します。</summary>
        /// <param name="dgv"><see cref="DataGridView"/>。</param>
        public void SetProfile(DataGridView dgv)
        {
            for (int i = 0; i < _profiles.Count && i < dgv.Columns.Count; i++)
                _profiles[i].SetProfile(dgv.Columns[i]);
        }

        /// <summary><see cref="DataGridViewColumn"/> の表示状態をシリアライズするクラス。</summary>
        public class DataGridViewColumnProfile : IXmlSerializable
        {
            /// <summary><see cref="DataGridViewColumn.Visible"/>。</summary>
            public bool Visible { get; set; }
            /// <summary><see cref="DataGridViewColumn.DisplayIndex"/>。</summary>
            public int DisplayIndex { get; set; }
            /// <summary><see cref="DataGridViewColumn.Width"/>。</summary>
            public int Width { get; set; }

            /// <summary><see cref="DataGridViewColumnProfile"/> の新しいインスタンスを初期化します。</summary>
            public DataGridViewColumnProfile()
            {
            }

            /// <summary><see cref="DataGridViewColumnProfile"/> の新しいインスタンスを初期化します。</summary>
            public DataGridViewColumnProfile(DataGridViewColumn col)
            {
                GetProfile(col);
            }

            /// <summary><see cref="DataGridViewColumn"/> から、<see cref="DataGridViewColumn"/> の表示状態を取得します。</summary>
            /// <param name="col"><see cref="DataGridViewColumn"/>。</param>
            public void GetProfile(DataGridViewColumn col)
            {
                Visible = col.Visible;
                DisplayIndex = col.DisplayIndex;
                Width = col.Width;
            }

            /// <summary><see cref="DataGridViewColumn"/> に、<see cref="DataGridViewColumn"/> の表示状態を設定します。</summary>
            /// <param name="col"><see cref="DataGridViewColumn"/>。</param>
            public void SetProfile(DataGridViewColumn col)
            {
                col.DisplayIndex = DisplayIndex;
                col.Width = Width;
                col.Visible = Visible;
            }

            /// <summary>予約済メソッド。</summary>
            public XmlSchema GetSchema()
            {
                return null;
            }

            /// <summary>XML から <see cref="DataGridViewColumn"/> の表示状態を読込みます。</summary>
            /// <param name="reader"><see cref="DataGridViewColumn"/> の表示状態を読込む元の <see cref="XmlReader"/>。</param>
            public void ReadXml(XmlReader reader)
            {
                try
                {
                    Visible = reader.ReadElementContentAsBoolean("Visible", string.Empty);
                    DisplayIndex = reader.ReadElementContentAsInt("DisplayIndex", string.Empty);
                    Width = reader.ReadElementContentAsInt("Width", string.Empty);
                }
                catch
                {
                    throw;
                }
            }

            /// <summary>XML に <see cref="DataGridViewColumn"/> の表示状態を保存します。</summary>
            /// <param name="writer"><see cref="DataGridViewColumn"/> の表示状態を保存する先の <see cref="XmlWriter"/>。</param>
            public void WriteXml(XmlWriter writer)
            {
                writer.WriteStartElement("Visible");
                writer.WriteValue(Visible);
                writer.WriteEndElement();
                writer.WriteStartElement("DisplayIndex");
                writer.WriteValue(DisplayIndex);
                writer.WriteEndElement();
                writer.WriteStartElement("Width");
                writer.WriteValue(Width);
                writer.WriteEndElement();
            }
        }

        /// <summary>予約済メソッド。</summary>
        public XmlSchema GetSchema()
        {
            return null;
        }

        /// <summary>XML から <see cref="DataGridViewColumn"/> の表示状態を読込みます。</summary>
        /// <param name="reader"><see cref="DataGridView"/> の列の表示状態を読込む元の <see cref="XmlReader"/>。</param>
        public void ReadXml(XmlReader reader)
        {
            reader.ReadStartElement("Profiles");
            reader.ReadStartElement("Count");
            var count = reader.ReadContentAsInt();
            reader.ReadEndElement();

            _profiles.Clear();
            for (int i = 0; i < count; i++)
            {
                reader.ReadStartElement("Profile");
                var p = new DataGridViewColumnProfile();
                p.ReadXml(reader);
                reader.ReadEndElement();
                _profiles.Add(p);
            }
        }

        /// <summary>XML に <see cref="DataGridViewColumn"/> の表示状態を保存します。</summary>
        /// <param name="writer"><see cref="DataGridView"/> の列の表示状態を保存する先の <see cref="XmlWriter"/>。</param>
        public void WriteXml(XmlWriter writer)
        {
            writer.WriteStartElement("Count");
            writer.WriteValue(_profiles.Count);
            writer.WriteEndElement();

            foreach (var p in _profiles)
            {
                writer.WriteStartElement("Profile");
                p.WriteXml(writer);
                writer.WriteEndElement();
            }
        }
    }
}